﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Net;
using System.Text.RegularExpressions;

namespace SynoManager.DownloadStation.Search
{
    /// <summary>
    /// Base class for Search Engine implementations where the query is executed through HTTP.
    /// </summary>
    /// <seealso cref="HttpSearchResultBase"/>
    public abstract class HttpSearchEngineBase : SearchEngineBase
    {
        /// <summary>
        /// Perform a (blocking) search for results matching the query.
        /// </summary>
        /// <param name="query">Query that will be passed to the search engine.</param>
        /// <returns>Array with <see cref="ISearchResult">SearchResults</see>.</returns>
        public override ISearchResult[] Search(string query)
        {
            // Create a webrequest through a (virtual) function.
            HttpWebRequest request = CreateWebRequest(query);

            // Set the UserAgent (to trick the website into thinking we're a real browser)
            request.UserAgent =
                @"User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; .NET CLR 2.0.50727)";

            // Get response
            HttpWebResponse response = (HttpWebResponse) request.GetResponse();
            Stream stream = response.GetResponseStream();
            StreamReader reader = new StreamReader(stream);
            string html = reader.ReadToEnd().Replace("\r", "");

            // Create the regular expression
            Regex regex = new Regex(Regex.Replace("\r", ""),
                                    RegexOptions.CultureInvariant | RegexOptions.IgnoreCase | RegexOptions.Compiled);

            // Get the matches
            var matches = regex.Matches(html);

            // Create results from the matches
            List<ISearchResult> results = new List<ISearchResult>();
            foreach (Match match in matches)
            {
                HttpSearchResultBase result = CreateResult(match);
                results.Add(result);
            }
            
            // Return the array with search results.
            return results.ToArray();
        }

        /// <summary>
        /// Creates a WebRequest for the specified query
        /// </summary>
        /// <remarks>Inheritors can override this function to add some provider specific parameters to the WebRequest.</remarks>
        /// <param name="query">Searchquery</param>
        /// <returns><see cref="HttpWebRequest" /> instance which can be used to execute the query</returns>
        protected virtual HttpWebRequest CreateWebRequest(string query)
        {
            string requestUri = String.Format(RequestUri, query);
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(requestUri);
            return request;
        }

        /// <summary>
        /// Creates a <see cref="HttpSearchResultBase">result</see> based on a Regex <see cref="Match" />.
        /// </summary>
        /// <param name="match">Regex Match</param>
        /// <returns>Search Result</returns>
        protected abstract HttpSearchResultBase CreateResult(Match match);

        /// <summary>
        /// Gets the RequestUri for queries.
        /// </summary>
        /// <remarks>This string is passed through <see cref="string.Format(string,object)"/> to add the query text. So add {0} somewhere in the query.</remarks>
        protected abstract string RequestUri { get; }

        /// <summary>
        /// Gets the Regular Expression that is used to parse the resulting (HTML) page into search results.
        /// </summary>
        /// <remarks>The Regular Expression should contain the following named groups: <code>Title</code>, <code>DownloadUrl</code>, <code>MoreInfoUrl</code>, <code>Seeders</code>, <code>Leechers</code>, <code>Size</code>, <code>Category</code>.</remarks>
        protected abstract string Regex { get; }
    }
}
